<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AegisX 企业级智能插件平台</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
    <script>
        // iframe相关函数 - 在head中定义确保全局可访问
        function hideIframeLoading(iframeName) {
            const loadingElement = document.getElementById(`${iframeName}-loading`);
            if (loadingElement) {
                loadingElement.style.display = 'none';
            }
        }
        
        function showIframeError(iframeName) {
            const loadingElement = document.getElementById(`${iframeName}-loading`);
            const errorElement = document.getElementById(`${iframeName}-error`);
            
            if (loadingElement) {
                loadingElement.style.display = 'none';
            }
            if (errorElement) {
                errorElement.style.display = 'flex';
            }
        }
        
        function reloadIframe(iframeName) {
            const iframe = document.getElementById(`${iframeName}-iframe`);
            const loadingElement = document.getElementById(`${iframeName}-loading`);
            const errorElement = document.getElementById(`${iframeName}-error`);
            
            if (errorElement) {
                errorElement.style.display = 'none';
            }
            if (loadingElement) {
                loadingElement.style.display = 'flex';
            }
            if (iframe) {
                const dataSrc = iframe.getAttribute('data-src');
                if (dataSrc) {
                    iframe.src = dataSrc;
                }
            }
        }
    </script>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            margin: 0;
        }
        
        .main-container {
            max-width: 1400px;
            margin: 20px auto;
            background: white;
            border-radius: 12px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.1);
            overflow: hidden;
            display: flex;
            flex-direction: column;
            min-height: calc(100vh - 40px);
        }
        
        .page-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 25px 35px;
            position: relative;
            overflow: hidden;
        }
        
        .page-header::before {
            content: '';
            position: absolute;
            top: -50%;
            right: -50%;
            width: 100%;
            height: 100%;
            background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
            animation: float 6s ease-in-out infinite;
        }
        
        @keyframes float {
            0%, 100% { transform: translateY(0px) rotate(0deg); }
            50% { transform: translateY(-10px) rotate(5deg); }
        }
        
        .header-content {
            text-align: center;
            position: relative;
            z-index: 1;
        }
        
        .page-header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
        }
        
        .page-header p {
            font-size: 1.2em;
            opacity: 0.9;
        }
        
        .user-info {
            position: absolute;
            top: 20px;
            right: 30px;
            display: flex;
            align-items: center;
            gap: 15px;
            z-index: 2;
        }
        
        .user-name {
            font-size: 1rem;
            opacity: 0.9;
        }
        
        .btn-outline-light {
            background: rgba(255,255,255,0.15);
            color: white;
            border: 1px solid rgba(255, 255, 255, 0.3);
            padding: 10px 20px;
            border-radius: 25px;
            transition: all 0.3s ease;
            text-decoration: none;
            font-size: 0.9rem;
            backdrop-filter: blur(10px);
            font-weight: 500;
        }
        
        .btn-outline-light:hover {
            background: rgba(255,255,255,0.25);
            color: white;
            text-decoration: none;
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.2);
            border-color: rgba(255,255,255,0.5);
        }
        
        .main-content {
            flex: 1;
            overflow-y: auto;
            display: flex;
        }
        
        .sidebar {
            width: 250px;
            min-width: 200px;
            background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);
            border-right: 1px solid #dee2e6;
            display: flex;
            flex-direction: column;
            padding: 20px 0;
            flex-shrink: 0;
            box-shadow: 2px 0 10px rgba(0,0,0,0.05);
        }
        
        .nav-item {
            padding: 15px 25px;
            cursor: pointer;
            transition: all 0.3s ease;
            border: none;
            background: none;
            font-size: 16px;
            text-align: left;
            border-left: 4px solid transparent;
            margin: 2px 10px;
            border-radius: 8px;
            font-weight: 500;
            color: #495057;
        }
        
        .nav-item:hover {
            background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
            border-left-color: #2196f3;
            transform: translateX(5px);
            box-shadow: 0 4px 12px rgba(33, 150, 243, 0.2);
        }
        
        .nav-item.active {
            background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
            color: white;
            border-left-color: #0d47a1;
            transform: translateX(5px);
            box-shadow: 0 6px 20px rgba(33, 150, 243, 0.4);
        }
        
        /* 水平导航菜单样式 */
        .navigation {
            background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
            border-bottom: 2px solid #e9ecef;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            padding: 0;
        }
        
        .nav-container {
            display: flex;
            justify-content: center;
            align-items: center;
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 20px;
        }
        
        .navigation .nav-item {
            display: flex;
            align-items: center;
            padding: 15px 25px;
            margin: 0 5px;
            cursor: pointer;
            transition: all 0.3s ease;
            border: none;
            background: none;
            font-size: 16px;
            font-weight: 500;
            color: #495057;
            text-decoration: none;
            border-radius: 8px;
            border-left: none;
            transform: none;
        }
        
        .navigation .nav-item:hover {
            background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
            color: #1976d2;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(33, 150, 243, 0.2);
        }
        
        .navigation .nav-item.active {
            background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
            color: white;
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(33, 150, 243, 0.4);
        }
        
        .nav-icon {
            margin-right: 8px;
            font-size: 18px;
        }
        
        .navigation .nav-item span {
            font-weight: 500;
        }
        
        /* 仪表盘样式 */
        .dashboard-header {
            text-align: center;
            margin-bottom: 30px;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
        }
        
        .dashboard-header h2 {
            margin: 0 0 10px 0;
            font-size: 2.2em;
            font-weight: 600;
        }
        
        .dashboard-header p {
            margin: 0;
            font-size: 1.1em;
            opacity: 0.9;
        }
        
        .dashboard-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
            gap: 20px;
            padding: 0 10px;
        }
        
        .dashboard-card {
            background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.08);
            transition: all 0.3s ease;
            overflow: hidden;
            border: 1px solid #e9ecef;
        }
        
        .dashboard-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 30px rgba(0,0,0,0.15);
        }
        
        .dashboard-card .card-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px;
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-bottom: 1px solid #dee2e6;
        }
        
        .dashboard-card .card-header h3 {
            margin: 0;
            font-size: 1.3em;
            font-weight: 600;
            color: #495057;
        }
        
        .dashboard-card .card-content {
            padding: 20px;
            min-height: 200px;
        }
        
        .btn-sm {
            padding: 6px 12px;
            font-size: 12px;
        }
        
        .quick-actions {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
            gap: 10px;
        }
        
        .quick-actions .btn {
            padding: 12px 16px;
            font-size: 14px;
            border-radius: 8px;
        }
        
        .btn-info {
            background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
            color: white;
        }
        
        .status-indicator {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            margin-right: 8px;
        }
        
        .status-running {
            background: #28a745;
            box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
        }
        
        .status-stopped {
            background: #dc3545;
            box-shadow: 0 0 10px rgba(220, 53, 69, 0.5);
        }
        
        .content {
            flex: 1;
            padding: 0;
            overflow: hidden;
            background: white;
            display: flex;
            flex-direction: column;
            min-width: 0;
        }
        
        .content-header {
            padding: 15px 20px;
            border-bottom: 1px solid #dee2e6;
            background: white;
        }
        
        .content-body {
            flex: 1;
            overflow: hidden;
            padding: 0;
        }
        
        .content-iframe {
            width: 100%;
            height: 100%;
            border: none;
            display: none;
        }
        
        .content-iframe.active {
            display: block;
        }
        
        .tab-content {
            display: none;
            height: 100%;
            overflow-y: auto;
            padding: 15px;
            width: 100%;
            box-sizing: border-box;
        }
        
        .tab-content.active {
            display: block;
        }
        
        .card {
            background: white;
            border-radius: 12px;
            border: 1px solid #dee2e6;
            box-shadow: 0 4px 20px rgba(0,0,0,0.08);
            transition: all 0.3s ease;
            margin-bottom: 20px;
        }
        
        .card:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 30px rgba(0,0,0,0.12);
        }
        
        .card-header {
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-bottom: 1px solid #dee2e6;
            padding: 1rem 1.25rem;
            border-radius: 12px 12px 0 0;
        }
        
        .card-body {
            padding: 1.25rem;
        }
        
        .plugin-item {
            background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%);
            border-radius: 12px;
            padding: 25px;
            margin-bottom: 15px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.08);
            transition: all 0.3s ease;
            border: 1px solid #e0e0e0;
        }
        
        .plugin-item:hover {
            transform: translateY(-4px);
            box-shadow: 0 8px 25px rgba(0,0,0,0.15);
            border-color: #2196f3;
        }
        
        .plugin-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }
        
        .plugin-name {
            font-size: 1.3em;
            font-weight: bold;
            color: #333;
        }
        
        .plugin-version {
            background: #28a745;
            color: white;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 0.8em;
        }
        
        .plugin-description {
            color: #666;
            margin-bottom: 15px;
        }
        
        .plugin-actions {
            display: flex;
            gap: 10px;
        }
        
        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.3s ease;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            position: relative;
            overflow: hidden;
        }
        
        .btn::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
            transition: left 0.5s;
        }
        
        .btn:hover::before {
            left: 100%;
        }
        
        .btn-primary {
            background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
            color: white;
        }
        
        .btn-success {
            background: linear-gradient(135deg, #4caf50 0%, #388e3c 100%);
            color: white;
        }
        
        .btn-warning {
            background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
            color: white;
        }
        
        .btn-danger {
            background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%);
            color: white;
        }
        
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(0,0,0,0.2);
        }
        
        .btn:active {
            transform: translateY(0);
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        
        .input-group {
            display: flex;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.05);
            border-radius: 8px;
            overflow: hidden;
        }
        
        .input-group input {
            flex: 1;
            padding: 12px 16px;
            border: 1px solid #e0e0e0;
            border-right: none;
            border-radius: 0;
            font-size: 14px;
            transition: all 0.3s ease;
            background: #fafafa;
        }
        
        .input-group input:focus {
            outline: none;
            border-color: #2196f3;
            background: white;
            box-shadow: inset 0 0 0 1px #2196f3;
        }
        
        .input-group button {
            border-radius: 0;
            border-left: none;
        }
        
        .result {
            background: linear-gradient(135deg, #e8f5e8 0%, #f0f8f0 100%);
            border-radius: 8px;
            padding: 20px;
            margin-top: 20px;
            border-left: 4px solid #4caf50;
            box-shadow: 0 4px 15px rgba(76, 175, 80, 0.1);
            transition: all 0.3s ease;
        }
        
        .result:hover {
            transform: translateY(-1px);
            box-shadow: 0 6px 20px rgba(76, 175, 80, 0.15);
        }
        
        .error {
            border-left-color: #f44336;
            background: linear-gradient(135deg, #ffebee 0%, #fce4ec 100%);
            box-shadow: 0 4px 15px rgba(244, 67, 54, 0.1);
        }
        
        .error:hover {
            box-shadow: 0 6px 20px rgba(244, 67, 54, 0.15);
        }
        
        .loading {
            text-align: center;
            padding: 30px;
            color: #666;
            font-size: 16px;
        }
        
        .loading::after {
            content: '';
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 2px solid #e0e0e0;
            border-top: 2px solid #2196f3;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-left: 10px;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .status-indicator {
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.2);
            animation: pulse 2s infinite;
        }
        
        @keyframes pulse {
            0% { transform: scale(1); opacity: 1; }
            50% { transform: scale(1.1); opacity: 0.8; }
            100% { transform: scale(1); opacity: 1; }
        }
        
        .status-running {
            background: linear-gradient(135deg, #4caf50 0%, #388e3c 100%);
        }
        
        .status-stopped {
            background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%);
        }
        
        /* 插件管理样式 */
        .plugin-management-header {
            text-align: center;
            margin-bottom: 30px;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-radius: 10px;
        }
        
        .plugin-management-header h2 {
            margin: 0 0 10px 0;
            font-size: 28px;
        }
        
        .plugin-management-header p {
            margin: 0;
            opacity: 0.9;
        }
        
        .plugin-toolbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 1px solid #e9ecef;
        }
        
        .toolbar-left {
            display: flex;
            gap: 10px;
        }
        
        .toolbar-right .search-box {
            display: flex;
            gap: 5px;
        }
        
        .search-box input {
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
            width: 200px;
        }
        
        .plugin-stats-overview {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 30px;
        }
        
        .stat-card {
            display: flex;
            align-items: center;
            padding: 20px;
            background: white;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            border-left: 4px solid #007bff;
        }
        
        .stat-icon {
            font-size: 30px;
            margin-right: 15px;
        }
        
        .stat-number {
            font-size: 24px;
            font-weight: bold;
            color: #333;
        }
        
        .stat-label {
            color: #666;
            font-size: 14px;
        }
        
        .plugin-list-container {
            background: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .plugin-list-container h3 {
            margin-top: 0;
            color: #333;
            border-bottom: 2px solid #007bff;
            padding-bottom: 10px;
        }
        
        .plugin-list {
            min-height: 200px;
        }
        
        /* 模态框样式 */
        .modal {
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.5);
            display: flex;
            justify-content: center;
            align-items: center;
        }
        
        .modal-content {
            background-color: white;
            border-radius: 10px;
            width: 90%;
            max-width: 500px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.3);
        }
        
        .modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px;
            border-bottom: 1px solid #eee;
        }
        
        .modal-header h3 {
            margin: 0;
            color: #333;
        }
        
        .close {
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
            color: #aaa;
        }
        
        .close:hover {
            color: #000;
        }
        
        .modal-body {
            padding: 20px;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        .form-group label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #333;
        }
        
        .form-group input,
        .form-group textarea {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
        }
        
        .form-actions {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
            margin-top: 20px;
        }
        
        .btn-secondary {
            background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%);
            color: white;
        }
        
        .btn-info {
            background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
            color: white;
        }
        
        .status-warning {
            background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
        }
        
        /* 数据库配置页面样式 */
        .config-card {
            border: none;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            border-radius: 12px;
            overflow: hidden;
        }

        .config-card .card-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-bottom: none;
            padding: 1rem 1.5rem;
        }

        .config-card .card-body {
            padding: 2rem;
        }

        .status-connected {
            background-color: #28a745;
        }

        .status-disconnected {
            background-color: #dc3545;
        }

        .btn-test {
            border-radius: 20px;
            padding: 0.5rem 1.2rem;
            font-weight: 500;
            transition: all 0.3s ease;
        }

        .btn-test:hover {
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
        }

        .form-label {
            font-weight: 600;
            color: #495057;
            margin-bottom: 0.5rem;
        }

        .form-control, .form-select {
            border-radius: 8px;
            border: 1px solid #ced4da;
            padding: 0.75rem 1rem;
            transition: all 0.3s ease;
        }

        .form-control:focus, .form-select:focus {
            border-color: #667eea;
            box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
        }

        .btn-group .btn {
            border-radius: 8px;
        }

        .btn-group .btn:first-child {
            border-top-right-radius: 0;
            border-bottom-right-radius: 0;
        }

        .btn-group .btn:last-child {
            border-top-left-radius: 0;
            border-bottom-left-radius: 0;
        }
        
        /* 响应式设计 */
        @media (max-width: 768px) {
            body {
                padding: 5px;
            }
            
            .container {
                border-radius: 8px;
                height: calc(100vh - 10px);
            }
            
            .nav {
                width: 60px;
                min-width: 60px;
            }
            
            .nav-item {
                padding: 12px 8px;
                font-size: 14px;
                text-align: center;
            }
            
            .header {
                padding: 15px 20px;
            }
            
            .header h1 {
                font-size: 1.8em;
            }
            
            .header p {
                font-size: 1em;
            }
            
            .user-info {
                position: relative;
                top: auto;
                right: auto;
                margin-top: 10px;
                justify-content: center;
            }
            
            .tab-content {
                padding: 15px;
            }
        }
        
        @media (max-width: 480px) {
            .nav {
                width: 50px;
                min-width: 50px;
            }
            
            .nav-item {
                padding: 10px 5px;
                font-size: 12px;
            }
            
            .header h1 {
                font-size: 1.5em;
            }
            
            .tab-content {
                padding: 10px;
            }
        }

        .loading-spinner {
            width: 1rem;
            height: 1rem;
            border: 2px solid #f3f3f3;
            border-top: 2px solid #2196f3;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        /* iframe统一样式 */
        .iframe-container {
            position: relative;
            width: 100%;
            height: 100%;
            background: #f8f9fa;
            border-radius: 8px;
            overflow: hidden;
        }
        
        .iframe-loading {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: rgba(248, 249, 250, 0.95);
            z-index: 10;
        }
        
        .loading-text {
            margin-top: 15px;
            color: #666;
            font-size: 14px;
            font-weight: 500;
        }
        
        .iframe-error {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: rgba(248, 249, 250, 0.95);
            z-index: 10;
        }
        
        .error-icon {
            font-size: 48px;
            color: #dc3545;
            margin-bottom: 15px;
        }
        
        .error-text {
            color: #666;
            font-size: 16px;
            margin-bottom: 20px;
            text-align: center;
        }
        
        .content-iframe {
            width: 100%;
            height: 100%;
            border: none;
            border-radius: 8px;
            background: white;
        }

        .alert {
            border-radius: 8px;
            border: none;
            margin-bottom: 1.5rem;
        }

        .alert-success {
            background-color: #d1edff;
            color: #0c5460;
        }

        .alert-danger {
            background-color: #f8d7da;
            color: #721c24;
        }

        .alert-warning {
            background-color: #fff3cd;
            color: #856404;
        }

        .alert-info {
            background-color: #d1ecf1;
            color: #0c5460;
        }

        .row {
            display: flex;
            flex-wrap: wrap;
            margin-right: -15px;
            margin-left: -15px;
        }

        .col-12, .col-lg-8, .col-md-10, .col-md-8, .col-md-4 {
            position: relative;
            width: 100%;
            padding-right: 15px;
            padding-left: 15px;
        }

        .col-12 {
            flex: 0 0 100%;
            max-width: 100%;
        }

        .col-md-4 {
            flex: 0 0 33.333333%;
            max-width: 33.333333%;
        }

        .col-md-8 {
            flex: 0 0 66.666667%;
            max-width: 66.666667%;
        }

        .col-md-10 {
            flex: 0 0 83.333333%;
            max-width: 83.333333%;
        }

        .col-lg-8 {
            flex: 0 0 66.666667%;
            max-width: 66.666667%;
        }

        .mx-auto {
            margin-left: auto;
            margin-right: auto;
        }

        .mb-4 {
            margin-bottom: 1.5rem;
        }

        .mb-3 {
            margin-bottom: 1rem;
        }

        .mb-1 {
            margin-bottom: 0.25rem;
        }

        .mb-0 {
            margin-bottom: 0;
        }

        .me-1 {
            margin-right: 0.25rem;
        }

        .me-2, .me-md-2 {
            margin-right: 0.5rem;
        }

        .d-flex {
            display: flex;
        }

        .d-grid {
            display: grid;
        }

        .d-md-flex {
            display: flex;
        }

        .align-items-center {
            align-items: center;
        }

        .justify-content-between {
            justify-content: space-between;
        }

        .justify-content-md-end {
            justify-content: flex-end;
        }

        .gap-2 {
            gap: 0.5rem;
        }

        .text-danger {
            color: #dc3545;
        }

        .text-success {
            color: #28a745;
        }

        .fw-bold {
            font-weight: bold;
        }

        .w-100 {
            width: 100%;
        }

        .card {
            position: relative;
            display: flex;
            flex-direction: column;
            min-width: 0;
            word-wrap: break-word;
            background-color: #fff;
            background-clip: border-box;
            border: 1px solid rgba(0, 0, 0, 0.125);
            border-radius: 0.25rem;
        }

        .card-header {
            padding: 0.75rem 1.25rem;
            margin-bottom: 0;
            background-color: rgba(0, 0, 0, 0.03);
            border-bottom: 1px solid rgba(0, 0, 0, 0.125);
        }

        .card-body {
            flex: 1 1 auto;
            padding: 1.25rem;
        }

        .card-title {
            margin-bottom: 0.75rem;
        }

        .card-text {
            margin-bottom: 0;
        }

        .input-group {
            position: relative;
            display: flex;
            flex-wrap: wrap;
            align-items: stretch;
            width: 100%;
        }

        .btn-close {
            box-sizing: content-box;
            width: 1em;
            height: 1em;
            padding: 0.25em 0.25em;
            color: #000;
            background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='m.235 1.027 1.027-.235 6.738 6.738 6.738-6.738 1.027.235-6.738 6.738 6.738 6.738-1.027.235-6.738-6.738-6.738 6.738-1.027-.235 6.738-6.738z'/%3e%3c/svg%3e") center/1em auto no-repeat;
            border: 0;
            border-radius: 0.25rem;
            opacity: 0.5;
        }

        .btn-close:hover {
            color: #000;
            text-decoration: none;
            opacity: 0.75;
        }

        .fade {
            transition: opacity 0.15s linear;
        }

        .show {
            opacity: 1;
        }

        .alert-dismissible {
            padding-right: 3rem;
        }

        .alert-dismissible .btn-close {
            position: absolute;
            top: 0;
            right: 0;
            z-index: 2;
            padding: 1.25rem 1rem;
        }

        .btn-outline-primary { color: #0d6efd; border-color: #0d6efd; background-color: transparent; }
        .btn-outline-primary:hover { color: #fff; background-color: #0d6efd; border-color: #0d6efd; }
        .btn-outline-secondary { color: #6c757d; border-color: #6c757d; background-color: transparent; }
        .btn-outline-secondary:hover { color: #fff; background-color: #6c757d; border-color: #6c757d; }
        .btn-outline-warning { color: #fd7e14; border-color: #fd7e14; background-color: transparent; }
        .btn-outline-warning:hover { color: #fff; background-color: #fd7e14; border-color: #fd7e14; }
        .btn-outline-info { color: #0dcaf0; border-color: #0dcaf0; background-color: transparent; }
        .btn-outline-info:hover { color: #000; background-color: #0dcaf0; border-color: #0dcaf0; }

        .btn-check {
            position: absolute;
            clip: rect(0, 0, 0, 0);
            pointer-events: none;
        }

        .btn-check:checked + .btn {
            color: #fff;
            background-color: #0d6efd;
            border-color: #0d6efd;
        }

        .form-text {
            margin-top: 0.25rem;
            font-size: 0.875em;
            color: #6c757d;
        }

        .spinner-border {
            display: inline-block;
            width: 2rem;
            height: 2rem;
            vertical-align: -0.125em;
            border: 0.25em solid currentColor;
            border-right-color: transparent;
            border-radius: 50%;
            animation: spinner-border 0.75s linear infinite;
        }

        .spinner-border-sm {
            width: 1rem;
            height: 1rem;
            border-width: 0.2em;
        }

        @keyframes spinner-border {
            to {
                transform: rotate(360deg);
            }
        }
    </style>
</head>
<body>
    <div class="main-container">
        <div class="page-header">
            <div class="user-info">
                <span class="user-name" sec:authentication="name">用户</span>
                <a href="/logout" class="btn btn-outline-light">登出</a>
            </div>
            <div class="header-content">
                <h1>🛡️ AegisX 企业级智能插件平台</h1>
                <p>基于Spring Boot + PF4J的插件化架构管理平台</p>
            </div>
        </div>
        
        <!-- 导航菜单 -->
        <nav class="navigation">
            <div class="nav-container">
                <div class="nav-item active" data-tab="dashboard" onclick="showTab('dashboard')">
                    <i class="bi bi-speedometer2 nav-icon"></i>
                    <span>仪表盘</span>
                </div>
                <div class="nav-item" data-tab="plugin-management" onclick="showTab('plugin-management')">
                    <i class="bi bi-plugin nav-icon"></i>
                    <span>插件管理</span>
                </div>
                <div class="nav-item" data-tab="database-management" onclick="showTab('database-management')">
                    <i class="bi bi-database nav-icon"></i>
                    <span>数据管理</span>
                </div>
                <div class="nav-item" data-tab="api-docs" onclick="showTab('api-docs')">
                    <i class="bi bi-book nav-icon"></i>
                    <span>API文档</span>
                </div>
            </div>
        </nav>
        
        <div class="main-content">
            <div class="content">
                <div id="dashboard" class="tab-content active">
                    <div class="iframe-container">
                        <div class="iframe-loading" id="dashboard-loading">
                            <div class="loading-spinner"></div>
                            <div class="loading-text">正在加载仪表盘...</div>
                        </div>
                        <iframe id="dashboard-iframe" data-src="/dashboard" class="content-iframe" onload="hideIframeLoading('dashboard')" onerror="showIframeError('dashboard')"></iframe>
                        <div class="iframe-error" id="dashboard-error" style="display: none;">
                            <div class="error-icon"><i class="bi bi-exclamation-triangle"></i></div>
                            <div class="error-text">加载失败，请稍后重试</div>
                            <button class="btn btn-primary" onclick="reloadIframe('dashboard')">重新加载</button>
                        </div>
                    </div>
                </div>
                <div id="plugin-management" class="tab-content">
                    <div class="iframe-container">
                        <div class="iframe-loading" id="plugin-management-loading">
                            <div class="loading-spinner"></div>
                            <div class="loading-text">正在加载插件管理...</div>
                        </div>
                        <iframe id="plugin-management-iframe" data-src="/plugin-management" class="content-iframe" onload="hideIframeLoading('plugin-management')" onerror="showIframeError('plugin-management')"></iframe>
                        <div class="iframe-error" id="plugin-management-error" style="display: none;">
                            <div class="error-icon"><i class="bi bi-exclamation-triangle"></i></div>
                            <div class="error-text">加载失败，请稍后重试</div>
                            <button class="btn btn-primary" onclick="reloadIframe('plugin-management')">重新加载</button>
                        </div>
                    </div>
                </div>
                <div id="database-management" class="tab-content">
                    <div class="iframe-container">
                        <div class="iframe-loading" id="database-management-loading">
                            <div class="loading-spinner"></div>
                            <div class="loading-text">正在加载数据管理...</div>
                        </div>
                        <iframe id="database-management-iframe" data-src="/database/config" class="content-iframe" onload="hideIframeLoading('database-management')" onerror="showIframeError('database-management')"></iframe>
                        <div class="iframe-error" id="database-management-error" style="display: none;">
                            <div class="error-icon"><i class="bi bi-exclamation-triangle"></i></div>
                            <div class="error-text">加载失败，请稍后重试</div>
                            <button class="btn btn-primary" onclick="reloadIframe('database-management')">重新加载</button>
                        </div>
                    </div>
                </div>
                <div id="api-docs" class="tab-content">
                    <div class="iframe-container">
                        <div class="iframe-loading" id="api-docs-loading">
                            <div class="loading-spinner"></div>
                            <div class="loading-text">正在加载API文档...</div>
                        </div>
                        <iframe id="api-docs-iframe" data-src="/api-docs" class="content-iframe" onload="hideIframeLoading('api-docs')" onerror="showIframeError('api-docs')"></iframe>
                        <div class="iframe-error" id="api-docs-error" style="display: none;">
                            <div class="error-icon"><i class="bi bi-exclamation-triangle"></i></div>
                            <div class="error-text">加载失败，请稍后重试</div>
                            <button class="btn btn-primary" onclick="reloadIframe('api-docs')">重新加载</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <script>

        
        // 通用错误处理函数
        function handleError(error, container, defaultMessage = '操作失败') {
            const message = error.message || defaultMessage;
            if (container) {
                container.innerHTML = `<div class="card error">${message}</div>`;
            } else {
                alert(message);
            }
        }
        
        // 通用API调用函数
        async function apiCall(url, options = {}) {
            try {
                const response = await fetch(url, options);
                return await response.json();
            } catch (error) {
                throw new Error(`网络错误: ${error.message}`);
            }
        }
        

        

        
        // 加载系统状态
        async function loadSystemStatus() {
            const container = document.getElementById('systemStatus');
            if (!container) return;
            container.innerHTML = '<div class="loading">正在加载系统状态...</div>';
            
            try {
                const result = await apiCall('/api/system/status');
                
                if (result.code === 200) {
                    const data = result.data;
                    let html = `
                        <div class="card">
                            <h4><i class="bi bi-pc-display"></i> 系统信息</h4>
                            <p><strong>状态:</strong> <span class="status-indicator status-running"></span>${data.status}</p>
                            <p><strong>版本:</strong> ${data.version}</p>
                            <p><strong>框架:</strong> ${data.framework}</p>
                            <p><strong>时间:</strong> ${new Date(data.timestamp).toLocaleString()}</p>
                        </div>
                        
                        <div class="card">
                            <h4><i class="bi bi-memory"></i> JVM 信息</h4>
                            <p><strong>总内存:</strong> ${(data.jvm.totalMemory / 1024 / 1024).toFixed(2)} MB</p>
                            <p><strong>已用内存:</strong> ${(data.jvm.usedMemory / 1024 / 1024).toFixed(2)} MB</p>
                            <p><strong>空闲内存:</strong> ${(data.jvm.freeMemory / 1024 / 1024).toFixed(2)} MB</p>
                            <p><strong>最大内存:</strong> ${(data.jvm.maxMemory / 1024 / 1024).toFixed(2)} MB</p>
                            <p><strong>处理器数量:</strong> ${data.jvm.processors}</p>
                        </div>
                    `;
                    container.innerHTML = html;
                } else {
                    handleError(new Error(result.message || '加载失败'), container);
                }
            } catch (error) {
                handleError(error, container);
            }
        }
        
        // 加载健康检查状态
        async function loadHealthCheck() {
            const container = document.getElementById('healthStatus');
            if (!container) return;
            container.innerHTML = '<div class="loading">正在加载健康检查状态...</div>';
            
            try {
                const result = await apiCall('/actuator/health');
                
                let html = `
                    <div class="card">
                        <h4><i class="bi bi-heart-pulse"></i> 应用健康状态</h4>
                        <p><strong>状态:</strong> <span class="status-indicator ${result.status === 'UP' ? 'status-running' : 'status-stopped'}"></span>${result.status}</p>
                    </div>
                `;
                
                if (result.components) {
                    html += '<div class="card"><h4><i class="bi bi-gear"></i> 组件状态</h4>';
                    for (const [key, value] of Object.entries(result.components)) {
                        html += `<p><strong>${key}:</strong> <span class="status-indicator ${value.status === 'UP' ? 'status-running' : 'status-stopped'}"></span>${value.status}</p>`;
                    }
                    html += '</div>';
                }
                
                container.innerHTML = html;
            } catch (error) {
                handleError(error, container, '加载失败');
            }
        }
        
        // 导航切换功能
        function showTab(tabId) {
            // 隐藏所有内容
            hideAllContent();
            
            // 显示选中的内容
            const targetTab = document.getElementById(tabId);
            if (targetTab) {
                targetTab.classList.add('active');
                targetTab.style.display = 'block';
                
                // 同时激活对应的iframe
                const iframe = document.getElementById(tabId + '-iframe');
                if (iframe) {
                    if (iframe.dataset.src) {
                        iframe.src = iframe.dataset.src;
                        delete iframe.dataset.src;
                    }
                    iframe.classList.add('active');
                }
            }
            
            // 更新导航激活状态
            updateActiveNav(tabId);
        }
        
        // 页面加载时默认显示仪表盘
        document.addEventListener('DOMContentLoaded', () => {
            showTab('dashboard');
        });
        
        // 隐藏所有内容
        function hideAllContent() {
            // 隐藏所有tab内容
            document.querySelectorAll('.tab-content').forEach(tab => {
                tab.classList.remove('active');
                tab.style.display = 'none';
            });
            // 隐藏所有iframe
            document.querySelectorAll('.content-iframe').forEach(iframe => {
                iframe.classList.remove('active');
            });
        }
        
        // 更新导航激活状态
        function updateActiveNav(activeId) {
            document.querySelectorAll('.nav-item').forEach(item => {
                item.classList.remove('active');
            });
            // 根据data-tab属性设置对应的导航项为激活状态
            const activeNavItem = document.querySelector(`[data-tab="${activeId}"]`);
            if (activeNavItem) {
                activeNavItem.classList.add('active');
            }
        }
        

        
        // 初始化所有iframe的加载状态
        function initializeIframes() {
            const iframes = ['dashboard', 'plugin-management', 'database-management', 'api-docs'];
            iframes.forEach(type => {
                const iframe = document.getElementById(type + '-iframe');
                const loading = document.getElementById(type + '-loading');
                if (iframe && loading) {
                    // 如果iframe还没有加载完成，显示加载状态
                    if (!iframe.contentDocument || iframe.contentDocument.readyState !== 'complete') {
                        loading.style.display = 'flex';
                    }
                }
            });
        }
        
        // iframe通信机制
        function sendMessageToIframe(iframeName, message) {
            const iframe = document.getElementById(iframeName + '-iframe');
            if (iframe && iframe.contentWindow) {
                iframe.contentWindow.postMessage({
                    type: 'PARENT_MESSAGE',
                    source: 'parent',
                    target: iframeName,
                    data: message
                }, '*');
            }
        }
        
        function sendMessageToAllIframes(message) {
            const iframes = ['dashboard', 'plugin-management', 'database-management', 'api-docs'];
            iframes.forEach(iframeName => {
                sendMessageToIframe(iframeName, message);
            });
        }
        
        // 监听来自iframe的消息
        window.addEventListener('message', function(event) {
            // 验证消息来源
            if (event.origin !== window.location.origin) {
                return;
            }
            
            const message = event.data;
            if (message && message.type === 'IFRAME_MESSAGE') {
                handleIframeMessage(message);
            }
        });
        
        // 处理来自iframe的消息
        function handleIframeMessage(message) {
            const { source, action, data } = message;
            
            switch (action) {
                case 'NAVIGATE_TO':
                    // 切换到指定页面
                    if (data && data.tab) {
                        showTab(data.tab);
                    }
                    break;
                    
                case 'SHOW_NOTIFICATION':
                    // 显示通知消息
                    if (data && data.message) {
                        showNotification(data.message, data.type || 'info');
                    }
                    break;
                    
                case 'UPDATE_TITLE':
                    // 更新页面标题
                    if (data && data.title) {
                        document.title = data.title;
                    }
                    break;
                    
                case 'RELOAD_IFRAME':
                    // 重新加载指定iframe
                    if (data && data.target) {
                        reloadIframe(data.target);
                    }
                    break;
                    
                case 'BROADCAST':
                    // 广播消息到其他iframe
                    if (data) {
                        const iframes = ['dashboard', 'plugin-management', 'database-management', 'api-docs'];
                        iframes.forEach(iframeName => {
                            if (iframeName !== source) {
                                sendMessageToIframe(iframeName, {
                                    type: 'BROADCAST',
                                    source: source,
                                    data: data
                                });
                            }
                        });
                    }
                    break;
                    
                default:
                    console.log('未处理的iframe消息:', message);
            }
        }
        
        // 显示通知消息
        function showNotification(message, type = 'info') {
            // 创建通知元素
            const notification = document.createElement('div');
            notification.className = `alert alert-${type === 'error' ? 'danger' : type === 'success' ? 'success' : type === 'warning' ? 'warning' : 'info'} alert-dismissible fade show position-fixed`;
            notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
            notification.innerHTML = `
                ${message}
                <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
            `;
            
            document.body.appendChild(notification);
            
            // 自动移除通知
            setTimeout(() => {
                if (notification.parentNode) {
                    notification.remove();
                }
            }, 5000);
        }
        
        // 数据库配置相关函数
        function toggleDbPassword() {
            const passwordInput = document.getElementById('dbPassword');
            const toggleIcon = document.getElementById('dbPasswordToggleIcon');
            
            if (passwordInput.type === 'password') {
                passwordInput.type = 'text';
                toggleIcon.className = 'bi bi-eye-slash';
            } else {
                passwordInput.type = 'password';
                toggleIcon.className = 'bi bi-eye';
            }
        }

        function showDbMessage(message, type = 'info') {
            const messageArea = document.getElementById('dbMessageArea');
            const alertClass = type === 'success' ? 'alert-success' : 
                              type === 'error' ? 'alert-danger' : 
                              type === 'warning' ? 'alert-warning' : 'alert-info';
            
            messageArea.innerHTML = `
                <div class="alert ${alertClass} alert-dismissible fade show" role="alert">
                    ${message}
                    <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
                </div>
            `;
            
            // 自动隐藏消息
            setTimeout(() => {
                const alert = messageArea.querySelector('.alert');
                if (alert) {
                    alert.remove();
                }
            }, 5000);
        }

        function getDbFormData() {
            const form = document.getElementById('dbConfigForm');
            const formData = new FormData(form);
            const data = {};
            
            for (let [key, value] of formData.entries()) {
                data[key] = value;
            }
            
            // 根据连接方式构建URL
            const configMode = document.querySelector('input[name="configMode"]:checked').value;
            if (configMode === 'separate') {
                const host = data.host || 'localhost';
                const port = data.port || '3306';
                const database = data.database || '';
                data.url = `jdbc:mysql://${host}:${port}/${database}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai`;
            }
            
            return data;
        }

        function testDbConnection() {
            const data = getDbFormData();
            const button = document.querySelector('button[onclick="testDbConnection()"]');
            const spinner = button.querySelector('.loading-spinner');
            
            // 显示加载状态
            button.disabled = true;
            spinner.style.display = 'inline-block';
            
            fetch('/database/api/test', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(data)
            })
            .then(response => response.json())
                .then(result => {
                    if (result.code === 200) {
                        showDbMessage('数据库连接测试成功！', 'success');
                        updateConnectionStatus(true, '连接正常');
                    } else {
                        showDbMessage(`连接测试失败: ${result.message}`, 'error');
                        updateConnectionStatus(false, '连接失败');
                    }
                })
            .catch(error => {
                showDbMessage(`连接测试异常: ${error.message}`, 'error');
                updateConnectionStatus(false, '连接异常');
            })
            .finally(() => {
                button.disabled = false;
                spinner.style.display = 'none';
            });
        }

        function testCurrentConnection() {
            fetch('/database/api/status')
            .then(response => response.json())
            .then(result => {
                if (result.code === 200 && result.data && result.data.connected) {
                    showDbMessage('当前数据库连接正常', 'success');
                    updateConnectionStatus(true, result.message || '连接正常');
                } else {
                    showDbMessage('当前数据库连接异常', 'error');
                    updateConnectionStatus(false, result.message || '连接异常');
                }
            })
            .catch(error => {
                showDbMessage(`检查连接状态失败: ${error.message}`, 'error');
                updateConnectionStatus(false, '状态未知');
            });
        }

        function updateConnectionStatus(connected, message) {
            const indicator = document.getElementById('dbStatusIndicator');
            const statusText = document.getElementById('dbStatusText');
            
            if (connected) {
                indicator.className = 'status-indicator status-connected';
                statusText.className = 'text-success fw-bold';
                statusText.textContent = message;
            } else {
                indicator.className = 'status-indicator status-disconnected';
                statusText.className = 'text-danger fw-bold';
                statusText.textContent = message;
            }
        }

        function resetDbConfig() {
            if (confirm('确定要重置所有配置吗？')) {
                document.getElementById('dbConfigForm').reset();
                document.getElementById('urlMode').checked = true;
                toggleConfigMode();
                showDbMessage('配置已重置', 'info');
            }
        }

        function reloadDataSource() {
            if (confirm('确定要重新加载数据源吗？这将断开当前连接。')) {
                fetch('/database/api/reload', {
                    method: 'POST'
                })
                .then(response => response.json())
                .then(result => {
                    if (result.code === 200) {
                        showDbMessage('数据源重新加载成功', 'success');
                        loadCurrentConfig();
                    } else {
                        showDbMessage(`重新加载失败: ${result.message}`, 'error');
                    }
                })
                .catch(error => {
                    showDbMessage(`重新加载异常: ${error.message}`, 'error');
                });
            }
        }

        function loadCurrentConfig() {
            fetch('/database/api/config')
            .then(response => response.json())
            .then(result => {
                if (result.code === 200) {
                    populateForm(result.data.config);
                    updateConnectionStatus(result.data.isConnected, result.data.isConnected ? '连接正常' : '连接断开');
                } else {
                    showDbMessage(`加载配置失败: ${result.message}`, 'error');
                }
            })
            .catch(error => {
                console.error('加载配置失败:', error);
                showDbMessage(`加载配置失败: ${error.message}`, 'error');
            });
        }

        function populateForm(config) {
            if (config.url) {
                document.getElementById('dbUrl').value = config.url;
            }
            if (config.username) {
                document.getElementById('dbUsername').value = config.username;
            }
            if (config.driverClassName) {
                document.getElementById('driverClassName').value = config.driverClassName;
            }
        }

        function toggleConfigMode() {
            const urlMode = document.getElementById('urlMode').checked;
            const urlConfig = document.getElementById('urlModeConfig');
            const separateConfig = document.getElementById('separateModeConfig');
            
            if (urlMode) {
                urlConfig.style.display = 'block';
                separateConfig.style.display = 'none';
            } else {
                urlConfig.style.display = 'none';
                separateConfig.style.display = 'block';
            }
        }
        
        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化所有iframe
            initializeIframes();
            
            // 默认显示仪表盘
            showTab('dashboard');
            
            // 为导航菜单添加点击事件
            document.querySelectorAll('.nav-item').forEach(item => {
                item.addEventListener('click', function(e) {
                    e.preventDefault();
                    const tabId = this.getAttribute('data-tab');
                    if (tabId) {
                        showTab(tabId);
                    }
                });
            });
            
            // 配置模式切换事件
            document.querySelectorAll('input[name="configMode"]').forEach(radio => {
                radio.addEventListener('change', toggleConfigMode);
            });
            
            // 表单提交事件
            const dbForm = document.getElementById('dbConfigForm');
            if (dbForm) {
                dbForm.addEventListener('submit', function(e) {
                    e.preventDefault();
                    
                    const data = getDbFormData();
                    const submitButton = this.querySelector('button[type="submit"]');
                    const spinner = submitButton.querySelector('.loading-spinner');
                    
                    // 显示加载状态
                    submitButton.disabled = true;
                    spinner.style.display = 'inline-block';
                    
                    fetch('/database/api/config', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(data)
                    })
                    .then(response => response.json())
                    .then(result => {
                        if (result.code === 200) {
                            showDbMessage('数据库配置保存成功！', 'success');
                            testCurrentConnection();
                        } else {
                            showDbMessage(`保存失败: ${result.message}`, 'error');
                        }
                    })
                    .catch(error => {
                        showDbMessage(`保存异常: ${error.message}`, 'error');
                    })
                    .finally(() => {
                        submitButton.disabled = false;
                        spinner.style.display = 'none';
                    });
                });
            }
            
            // 页面加载时获取当前配置
            if (document.getElementById('dbConfigForm')) {
                loadCurrentConfig();
            }
        });
    </script>
            </div>
        </div>
    </div>
    
    <!-- Bootstrap JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>